%{
// Trabalho de Compiladores - 2009.2
// SimpleLogo - Anderson Carvalho, Caio Almeida e Rafael
// Analisador Sintático e Semântico

// Bibliotecas necessárias
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

// Tratamento de erros
int errorline = 1;

void yyerror(const char *str)
{
	

	printf("Erro na análise sintática próximo à linha %d\n", errorline);
	
	exit(0);
}
 
int yywrap()
{
        return 1;
}

// Arquivo onde será código intermediário
FILE *rubyfile;

%}

// Identificadores da linguagem
%union {
	char id[1024];
}

// Tokens
%token if_ repeat_ for_ wait_ penup pendown turnleft turnright direction go gox goy reset pencolor penwidth canvassize canvascolor intnum variable while_ openpar closepar openbracket closebracket commas to_ true_ false_ greater less equal more minus mult division and_ or_ forward backward write_ text_
%%

programa:
	cmd {errorline++;} recursivecmd {
	fprintf(rubyfile, "    end\n\nend\n\nGtk.init\nwindow = Compiler.new\nGtk.main"); fclose(rubyfile);}
	;

recursivecmd:
	/* Empty */
	| cmd {errorline++;} recursivecmd	
	;

codeblock:
	recursivecmd
	;

cmdif:
	if_ openpar boolexp closepar openbracket {fprintf(rubyfile, "if (%s)\n", $<id>3);} codeblock closebracket {fprintf(rubyfile, "end\n");}
	;

cmdrepeat:
	repeat_ matexp {
		if (atoi($<id>2) < 0) printf("Warning: Parâmetro para comando repeat deve ser maior que 0\n");}
	 	openbracket {
			fprintf(rubyfile, "(%s).repeat {\n", $<id>2);}
			codeblock closebracket { fprintf(rubyfile, "}\n");
		}	
	;


cmdfor:
	for_ matattr to_ matexp openbracket {
		char pvar[30];
		char pexp[30];
		char* result;
		result = strtok($<id>2, "?");
		strcpy(pvar, result);			
		result = strtok(NULL, "?");
		strcpy(pexp, result);
		fprintf(rubyfile, "for %s in %s..%s\n",pvar, pexp, $<id>4); 
	}
	codeblock closebracket {fprintf(rubyfile, "end\n");}
	;


cmdwait:
	wait_ matexp {
		fprintf(rubyfile,"wait(%s)\n", $<id>2);
	}
	;

cmdwhile:
	while_ openpar boolexp closepar openbracket{fprintf(rubyfile, "while (%s) do\n",$<id>3);} 
	codeblock closebracket {
		fprintf(rubyfile, "end\n");
	}
	;

cmdpenup:
	penup {fprintf(rubyfile, "penup\n");}
	;

cmdpendown:
	pendown {fprintf(rubyfile, "pendown\n");}
	;

cmdturnleft:
	turnleft matexp {
		if ((atoi($<id>2) > 360)||(atoi($<id>2) < 0))
			printf("Warning: Ângulo inválido para turnleft\n");
         	else {
			fprintf(rubyfile, "turnleft(%s.to_i)\n", $<id>2);
		}
	}
	;

cmdturnright:
	turnright matexp {
		if ((atoi($<id>2) > 360)||(atoi($<id>2) < 0))
			printf("Warning: Ângulo inválido para turnright\n");
	        else {
			fprintf(rubyfile, "turnright(%s.to_i)\n", $<id>2);
		}
	} 
	;

cmddirection:
	direction matexp {
		if ((atoi($<id>2) > 360)||(atoi($<id>2) < 0))
			printf("Warning: Ângulo inválido para direction\n");
	        else {
			fprintf(rubyfile, "direction(%s.to_i)\n", $<id>2);
		}
	} 
	;

cmdgo:
	go matexp commas matexp {fprintf(rubyfile, "go %s, %s\n", $<id>2, $<id>4);}
	;

cmdgox:
	gox matexp {fprintf(rubyfile, "gox %s\n", $<id>2);}
	;

cmdgoy:
	goy matexp {fprintf(rubyfile, "goy %s\n", $<id>2);}
	;

cmdreset:
	reset {fprintf(rubyfile, "reset\n");}
	;

cmdpencolor:
	pencolor matexp commas matexp commas matexp {
		if ((atoi($<id>2) > 65535 )||( atoi($<id>4) > 65535 )||( atoi($<id>6) > 65535 )||( atoi($<id>2) < 0 )||( atoi($<id>4) < 0 )||( atoi($<id>6) < 0))
			printf("Warning: Valores inválidos para cor\n.");
		else
			fprintf(rubyfile, "pencolor %s, %s, %s\n", $<id>2, $<id>4, $<id>6);
	}
	;

cmdpenwidth:
	penwidth matexp {fprintf(rubyfile, "penwidth(%s.to_i)\n", $<id>2);}
	;

cmdcanvassize:
	canvassize matexp commas matexp {fprintf(rubyfile, "canvassize %s",$<id>2);}
	;

cmdcanvascolor:
	canvascolor matexp commas matexp commas matexp {
		if ((atoi($<id>2) > 65535 )||( atoi($<id>4) > 65535 )||( atoi($<id>6) > 65535 )||( atoi($<id>2) < 0 )||( atoi($<id>4) < 0 )||( atoi($<id>6) < 0))
			printf("Warning: Valores inválidos para cor\n.");
		else
			fprintf(rubyfile, "canvascolor %s, %s, %s", $<id>2, $<id>3, $<id>4);
	}
	;

cmdforward:
	forward matexp {fprintf(rubyfile, "forward(%s.to_i)\n", $<id>2);}
	;

cmdbackward:
	backward matexp {fprintf(rubyfile, "backward(%s.to_i)\n", $<id>2);}
	;

cmdwrite:
        write_ text_ {
        	fprintf(rubyfile, "showtext(%s)\n", $<id>2);
        }
        ;

intnumvalue:
	variable {strcpy($<id>$,($<id>1+1));}
	|intnum {strcpy($<id>$,$<id>1);}
	| minus intnum {strcat($<id>$, "-"); strcat($<id>$, $<id>1);}
	;

boolvalue:
	intnumvalue {strcpy($<id>$,$<id>1);}
	|true_ {strcpy($<id>$,$<id>1);}
	|false_ {strcpy($<id>$,$<id>1);}
	;

cmd:
	matattr
	|cmdif
	|cmdrepeat
	|cmdfor
	|cmdwait
	|cmdwhile
	|cmdpenup
	|cmdpendown
	|cmdturnleft
	|cmdturnright
	|cmddirection   
	|cmdgo
	|cmdgox
	|cmdgoy
	|cmdreset 
	|cmdpencolor
	|cmdpenwidth
	|cmdcanvassize
	|cmdcanvascolor
	|cmdforward
	|cmdbackward
	|cmdwrite
	;		

matexp:
	matexp more expm2 {strcat($<id>1, "+"); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);}
        | matexp minus expm2 {strcat($<id>1, "-"); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);}
	| expm2 {strcpy($<id>$,$<id>1);}
	;

expm2:
	expm2 mult expm3 {strcat($<id>1, "*"); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);}
	| expm2 division expm3 {strcat($<id>1, "/"); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);}
	| expm3 {strcpy($<id>$,$<id>1);}
	;

expm3:
	openpar matexp closepar {strcat($<id>2, ")"); strcpy($<id>$, "("); strcat($<id>$,$<id>2);}
	| intnumvalue {strcpy($<id>$,$<id>1); }
	;

matattr:
	variable equal matexp{
	fprintf(rubyfile, "%s = %s\n",($<id>1+1), $<id>3);
	strcpy($<id>$,($<id>1+1));
	strcat($<id>$,"?");
	strcat($<id>$, $<id>3);
	strcat($<id>$,"?");
	}
        ;

boolexp:
	boolexp equal equal expb2{strcat($<id>1, "=="); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);} 
	| boolexp and_ expb2{strcat($<id>1, " and "); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);} 
	| boolexp or_ expb2 {strcat($<id>1, " or "); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);} 
	| expb2 {strcpy($<id>$,$<id>1);}
	;

expb2:
	expb2 greater expb3 {strcat($<id>1, ">"); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);}
	|expb2 less expb3{strcat($<id>1, "<"); strcat($<id>1, $<id>3); strcpy($<id>$,$<id>1);}
	|expb3{strcpy($<id>$,$<id>1);}
	;

expb3:
	openpar boolexp closepar{strcat($<id>2, ")"); strcpy($<id>$, "("); strcat($<id>$,$<id>2);}
	| boolvalue {strcpy($<id>$,$<id>1);}
	;

%%
#include <stdio.h>

int main( )
{
	
	rubyfile = fopen("intermediario.rb", "w");
	fprintf(rubyfile,"#!/usr/bin/ruby\n\nrequire 'lib'\n\nclass Compiler < Gtk::Window\n\ndef run_cmds\n\n");
 	return yyparse();
}
